#ifndef __UTIL_H__
#define __UTIL_H__

#include "position.h"
#include <string>
#include <cstddef> // size_t

typedef char MapElementType;

enum OrigMapElement
{
  START   = 'S', ///< Start point
  GOAL    = 'G', ///< End point
  BLOCK   = 'X', ///< Road block
  ROAD    = '.', ///< attainable road
  UNKNOWN_MAP_ELEMENT_TYPE = '?'
};

/** Map to test the algorithm: 2D matrix of OrigMapElement objects
 * 2D map coordinates in the matrix (See also StateDiagram::Direction):
 * O ----------------> Y
 * |         LEFT
 * |          ^
 * |          |
 * |  DOWN <--+--> UP
 * |          |
 * |          v
 * |        RIGHT
 * v
 * X
 * */
class TestMap
{
  typedef std::vector<MapElementType> MapLineType;
  typedef std::vector<MapLineType> MapType;
private:
  MapType map_; ///< full map
  size_t map_size_; ///< number of map grids
  Position start_; ///< start point
  Position goal_;  ///< goal point
public:
  ///< 1) Construct a map by reading a text file.
  ///< 2) Pick up the start and goal point.
  explicit TestMap(const char *filename);
  /// copy constructor
  TestMap(const TestMap &tmap)
    : map_(tmap.map_), map_size_(tmap.map_size_),
    start_(tmap.start_), goal_(tmap.goal_) {}
  ~TestMap() {}
public:
  /// Return the number of map grids
  size_t size() const { return map_size_; }
  size_t x_size() const { return map_.size(); }
  size_t y_size() const { return map_.begin()->size(); }
  /// Look up the type of a 2D coordinate on the map
  const MapElementType &at(const size_t x, const size_t y) const
    { return map_.at(x).at(y); }
  /// Return a reference to an element of the 2D map
  MapElementType &at(const size_t x, const size_t y)
    { return map_.at(x).at(y); }
  /// Return constant reference to the start position.
  const Position &start() const { return start_; }
  /// Return constant reference to the goal position.
  const Position &goal()  const { return goal_;  }
  /// Print this map on the screen
  void print(const std::string &banner = "") const;
private:
  /// Parse one line of the input file; return next current map line number.
  size_t parseLine(const std::string &str, const size_t currentLineNo);
};

#endif //__UTIL_H__
